C# examples of using the SDK

Blueprint examples

Action Object examples

Executor examples

CAF examples

Blueprint Examples

Configuring a blueprint – Adding a new sink block

C#:

String fileName = "C:\\MyBlueprint.mgd";

// NOTE: RealtimeActionObjects will also load Blueprint properties 

RealtimeActionObject myActionObject = new RealtimeActionObject(fileName);
SuperBlock rootSuperBlock = (SuperBlock)(myActionObject.Blueprint.RootSuperBlock);
OptimizedDatabaseSinkBlock optimizedDBSink = new OptimizedDatabaseSinkBlock();
optimizedDBSink.Name = "My_New_Optimised_Database_Sink";
rootSuperBlock.Blocks.Add(optimizedDBSink);

Configuring a blueprint – Configuring a newly added block

C#:

String fileName = "C:\\MyBlueprint.mgd";

// NOTE: RealtimeActionObjects will also load Blueprint properties 

RealtimeActionObject myActionObject = new RealtimeActionObject(fileName);
SuperBlock rootSuperBlock = (SuperBlock)(myActionObject.Blueprint.RootSuperBlock);
OptimizedDatabaseSinkBlock optimizedDBSink = new OptimizedDatabaseSinkBlock();
optimizedDBSink.Name = "My_New_Optimised_Database_Sink";
rootSuperBlock.Blocks.Add(optimizedDBSink);
optimizedDBSink.AutoReconnect = false;
optimizedDBSink.ClearTablesOnStartup = true;

optimizedDBSink.Connection.ConnectionString =
    "Provider=SQLNCLI10.1;Integrated Security=SSPI;Persist Security Info=False;User ID=\"\";Initial Catalog=TESTING;Data Source=(LOCAL)\\SQLEXPRESS;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Workstation ID=WIN-12HMNUCTJ3S;Initial File Name...";

optimizedDBSink.SaveBehavior = OptimizedDatabaseSinkBlock.SaveBehaviorKind.OnTimestampChange;
optimizedDBSink.SavedTimestampReference = OptimizedDatabaseSinkBlock.TimestampKind.Local;
optimizedDBSink.Connection.FieldsTable = "My_Fields";
optimizedDBSink.Connection.ValuesTable = "My_Field_Values";

Configuring a blueprint – Connecting a block

C#:

String fileName = "C:\\MyBlueprint.mgd";
RealtimeActionObject myActionObject = new RealtimeActionObject(fileName);
SuperBlock rootSuperBlock = (SuperBlock)(myActionObject.Blueprint.RootSuperBlock);
OptimizedDatabaseSinkBlock optimizedDBSink = (OptimizedDatabaseSinkBlock)rootSuperBlock.FindBlockByName("My_DatabaseSink_Block");
DotNetScriptingBlock dotNETScript = (DotNetScriptingBlock)rootSuperBlock.FindBlockByName("My_Script_Block");
dotNETScript.OutputPorts[0].Connect(optimizedDBSink.InputPorts[0]);

 

Action Object Examples

Creating a Real-time Action Object - Loading from XML

C#:

String fileName = "C:\\MySourceBlueprint.xml";
RealtimeActionObject myActionObject = new RealtimeActionObject(fileName);

Creating a Real-time Action Object - Loading from a blueprint MGD file

C#:

String fileName = "C:\\MySourceBlueprint.mgd";
RealtimeActionObject myActionObject = new RealtimeActionObject(fileName);

 

Check runnability

C#:

String fileName = "C:\\MySourceBlueprint.xml";
RealtimeActionObject myActionObject = new RealtimeActionObject(fileName);
Dictionary<BlockBase, List<String>> blockMessageListDictionary = new Dictionary<BlockBase, List<String>>();
bool blueprintRunnnable = myActionObject.Blueprint.RunnabilityCheck(ref blockMessageListDictionary, null /* mediaMapping not used */);

 

Check runnability and write results to file

C#:

String fileName = "C:\\MySourceBlueprint.xml";
RealtimeActionObject myActionObject = new RealtimeActionObject(fileName);
Dictionary<BlockBase, List<String>> blockMessageListDictionary = new Dictionary<BlockBase, List<String>>();
bool blueprintRunnnable = myActionObject.Blueprint.RunnabilityCheck(ref blockMessageListDictionary, null /* mediaMapping not used */);

if (!blueprintRunnnable)
{
    TextWriter runnabilityResults = new StreamWriter( "C:\\runnabilityResults.txt" );
    String error = String.Empty;
    foreach (BlockBase block in blockMessageListDictionary.Keys)
    {
        error += System.Environment.NewLine + block.Name + " : ";
        foreach (string message in blockMessageListDictionary[block])
        {
            error += message + System.Environment.NewLine;
        }
    }

    runnabilityResults.WriteLine(error);
    runnabilityResults.Close();
}

 

Exporting a blueprint to XML

C#:

String fileName = "C:\\MySourceBlueprint.mgd";
RealtimeActionObject myActionObject = new RealtimeActionObject(fileName);
String XMLFile = "C:\\MyXMLBlueprint.xml";
myActionObject.Export( XMLFile, ActionObjectFileKind.Blueprint );

 

Deploying a Real-time Action Object – No runnability check

C#:

String fileName = "C:\\MySourceBlueprint.mgd";
RealtimeActionObject myActionObject = new RealtimeActionObject(fileName);
myActionObject.Name = “My Action Object”;
ActionObjectServer server = new ActionObjectServer();
DeployedActionObject realtimeDeployedActionObject = server.Deploy( myActionObject );

 

Deploying a Real-time Action Object – With runnability check

C#:

String fileName = "C:\\MySourceBlueprint.mgd";
RealtimeActionObject myActionObject = new RealtimeActionObject(fileName);
myActionObject.Name = “My Action Object”;
Dictionary<BlockBase, List<String>> blockMessageListDictionary = new Dictionary<BlockBase, List<String>>();
bool blueprintRunnnable = myActionObject.Blueprint.RunnabilityCheck(ref blockMessageListDictionary, null);
if (blueprintRunnnable)
{
    ActionObjectServer server = new ActionObjectServer();
    DeployedActionObject realtimeDeployedActionObject = server.Deploy( myActionObject );
}
else
{
    System.Diagnostics.Debug.Fail("Blueprint is not runnable");
}

 

Deploying a Scheduled Action Object – Blueprints with historical data sources

C#:

String fileName = "C:\\MySourceBlueprint.mgd";
ScheduledActionObject scheduledActionObject = new ScheduledActionObject(fileName);
scheduledActionObject.Name = “My Action Object”;

// Reconfigure all sources to have a window of 2 hours
foreach (var item in scheduledActionObject.SourceWindowSizeOffsetMap.Values)
{
    item.WindowSize = TimeSpan.FromHours(2.0);
    item.Offset = TimeSpan.Zero;
}

// Specify the trigger type: Scheduled, Once-off etc…
scheduledActionObject.Trigger = Proficy.CSense.SDK.ScheduledActionObjectTriggerKind.Scheduled;
scheduledActionObject.StartTime = DateTime.Now;
scheduledActionObject.SchedulePeriod = new TimeSpan(0, 2, 0);
ActionObjectServer server = new ActionObjectServer();
DeployedActionObject scheduledDeployedActionObject = server.Deploy(scheduledActionObject);

 

Deploying Event-based Action Objects

C#:

String fileName = "C:\\MyBlueprint.mgd";
EventBasedActionObject eventBasedActionObject = new EventBasedActionObject(fileName);
eventBasedActionObject.Name = “My Event based Action Object”;
ActionObjectServer server = new ActionObjectServer();
DeployedEventBasedActionObject deployedEventBasedActionObject = (DeployedEventBasedActionObject)server.Deploy(eventBasedActionObject);

 

Execute a deployed Event-based Action Object

C#:

// Get a list of available Event-based Action Objects
ActionObjectServer server = new ActionObjectServer();
server.Refresh();

// Execute the first Event-based Action Object
var list = server.EventBasedActionObjects;
if (list.Count > 0)
{
    list[0].Execute(DateTime.Now, “SDK Application”);
}

 

Managing Real-time Action Objects – Deploying and removing an Action Object

C#:

String fileName = "C:\\MyBlueprint.mgd";
RealtimeActionObject realtimeActionObject = new RealtimeActionObject(fileName);
realtimeActionObject.Name = “My Action Object Name”;
ActionObjectServer server = new ActionObjectServer();
DeployedActionObject realtimeDeployedActionObject = server.Deploy(realtimeActionObject);
server.Remove(realtimeDeployedActionObject);

 

Managing Real-time Action Objects – Stopping all Action Objects

C#:

ActionObjectServer server = new ActionObjectServer();
server.Refresh();
if (server != null)
{
    foreach (DeployedActionObject deployedActionObject in server.RealtimeActionObjects)
    {
        server.Remove(deployedActionObject);
    }
}

Executor Examples

Using the ISVExecutor class in the SDK

C#:

// Load in your custom blueprint
Blueprint myBlueprint = BlueprintCreator.ImportBlueprint("MyArchitectBlueprint.mgd");

// Create ISV Executor
ISVExecutor isvExecutor = new ISVExecutor(myBlueprint);

// Alternative way to construct the ISVExecutor:
ISVExecutor isvExecutor = new ISVExecutor("MyISVFile.isv");

// Get the current time in a UTC format
DateTime executeTime = new DateTime(DateTime.Now.Ticks, DateTimeKind.Utc);

// Setup input fields for each input of your ISV; in this case 3 inputs
isvExecutor.Inputs[0].Set(executeTime, 4.83, ISVExecutor.GoodQuality); // Set Double Value of Good Quality
isvExecutor.Inputs[1].Set(executeTime, 587, ISVExecutor.GoodQuality); // Set Integer Value of Good Quality
isvExecutor.Inputs[2].Set(executeTime, "My String", ISVExecutor.BadQuality); // New String Value of Bad quality

// Execute the ISV object with the configured inputs
isvExecutor.Execute(executeTime);

// Read the values back
double outputDouble = (double) isvExecutor.Outputs[0].Value;
int outputInteger = (int) isvExecutor.Outputs[1].Value;
string outputString = (string) isvExecutor.Outputs[2].Value;

// Execute the ISV object again at a newer timestamp
executeTime = new DateTime(DateTime.Now.Ticks, DateTimeKind.Utc);
isvExecutor.Execute(executeTime);

// Write a custom program loop to call isvExecutor.Execute(DateTime executeTime) as many times as you want to produce new outputs

// If needed, save the internal ISV object to a new .isv file
isvExecutor.Save("NewISVFile.isv");

 

Using the Source Block Executor class in the SDK

C#:

// Create a source block and initialize the HistoricalSourceBlockExecutor class
TextSourceBlock textSourceBlock = new TextSourceBlock();
textSourceBlock.Connection.Filename = @"c:\myFolder\myFile.txt";

HistoricalSourceBlockExecutor myHistoricalSourceBlockExecutor = new HistoricalSourceBlockExecutor(textSourceBlock); // Note: Any source block can be passed to this constructor

// Setup events on a configured Historical Source Executor
myHistoricalSourceBlockExecutor.NotifyMessageLogged += new EventHandler<NotifyMessageLoggedEventArgs>(MyNotifyMessageEventHandlerMethod);

void MyNotifyMessageEventHandlerMethod(object sender, NotifyMessageLoggedEventArgs e)
{
   // Get event notifications here for messages logged by the block during execution
   Console.WriteLine("Logged message = " + e.Message);
}

// Execute the Historical Block used in this example, the block is executed as long as it has data.
while (myHistoricalSourceBlockExecutor.HasMoreData)
{
   myHistoricalSourceBlockExecutor.Execute();
}

// Show output values of the historical source after execution
foreach (FieldValue field in myHistoricalSourceBlockExecutor.FieldValues)
{
   Console.WriteLine("Field Name = " + field.Name);
   Console.WriteLine("Field Value = " + field.Value);
}

 

Using the Real-time Source Block Executor class in the SDK

C#:

// Create a source block and initialize the RealtimeSourceBlockExecutor class
TextSourceBlock textSourceBlock = new TextSourceBlock();
textSourceBlock.Connection.Filename = @"c:\myFolder\myFile.txt";

RealtimeSourceBlockExecutor myRealtimeSourceBlockExecutor = new RealtimeSourceBlockExecutor(textSourceBlock); // Note: Any source block can be passed to this constructor

// Setup events on a configured Realtime Source Executor
myRealtimeSourceBlockExecutor.NotifyMessageLogged += new EventHandler<NotifyMessageLoggedEventArgs>(MyNotifyMessageEventHandlerMethod);
myRealtimeSourceBlockExecutor.NotifyOverloading += new EventHandler<RealtimeSourceBlockExecutor.NotifyOverloadingEventArgs>(MyNotifyOverloadingEventHandlerMethod);
myRealtimeSourceBlockExecutor.NotifyValuesRead += new EventHandler<RealtimeSourceBlockExecutor.NotifyValuesReadEventArgs>(MyNotifyValuesReadEventHandlerMethod);

void MyNotifyMessageEventHandlerMethod(object sender, NotifyMessageLoggedEventArgs e)
{
   // Get event notifications here for messages logged by the block during execution
   Console.WriteLine("Logged message = " + e.Message);
}

void MyNotifyOverloadingEventHandlerMethod(object sender, RealtimeSourceBlockExecutor.NotifyOverloadingEventArgs e)
{
   // Get event notifications here for when overloading occurs during execution
   Console.WriteLine("Overload count = " + e.OverloadCount.ToString());
}

void MyNotifyValuesReadEventHandlerMethod(object sender, RealtimeSourceBlockExecutor.NotifyValuesReadEventArgs e)
{
    // Get event notifications here for new values read by the block during execution
   foreach (KeyValuePair<string, FieldValue> pair in e.FieldValues)
   {
       Console.WriteLine("Field Name = " + pair.Key);
       Console.WriteLine("Field Value =" + pair.Value.Value);
   }
}

// Run and stop the Realtime Source Executor
myRealtimeSourceBlockExecutor.StartExecution();

// Add code to wait for a specified amount of time or wait until the source finishes execution by itself (this will not happen with all sources!)
if (myRealtimeSourceBlockExecutor.IsExecuting)
{
   myRealtimeSourceBlockExecutor.StopExecution();
}

 

Using the Sink Block Executor class in the SDK

C#:

// Create a sink block and initialize the SinkBlockExecutor class
TextSinkBlock textSinkBlock = new TextSinkBlock();
FieldCollection<Field> myFieldsToWrite = new FieldCollection<Field>();

myFieldsToWrite.Add(new Field("Field1", Field.FieldKind.Double));
myFieldsToWrite.Add(new Field("Field2", Field.FieldKind.Integer));
myFieldsToWrite.Add(new Field("Field3", Field.FieldKind.String));

SinkBlockExecutor mySinkBlockExecutor = new SinkBlockExecutor(textSinkBlock, myFieldsToWrite); // Note: any sink block can be added except the OPCServerSinkBlock!

// Setup events on a configured Sink Executor
mySinkBlockExecutor.NotifyMessageLogged += new EventHandler<NotifyMessageLoggedEventArgs>(mySinkBlockExecutor_NotifyMessageLogged);

void MyNotifyMessageEventHandlerMethod(object sender, NotifyMessageLoggedEventArgs e)
{
    // Get event notifications here for messages logged by the block during execution
    Console.WriteLine("Logged message = " + e.Message);
}

// Execute the sink block used
DateTime myExecuteTime = DateTime.Now;
mySinkBlockExecutor.Execute(myExecuteTime);

 

CAF Examples

Calling the Analytic Executor/Creating analytic block

C#:

Proficy.CSense.SDK.Runtime.AnalyticRepository analyticRepository = new Proficy.CSense.SDK.Runtime.AnalyticRepository();
List<AnalyticRepository.Analytic> analyticList = analyticRepository.GetAvailableAnalytics();

// Calling the analytic executor
// keepstate is a bool
// true = keeps the executor in memory and therefor can continue execution from its last execute call
// false = creates a new executor on each execute therefor cannot continue execution from its last execute call
AnalyticExecutor executor = AnalyticExecutor::Create( analyticList[0], true);

// Creating analytic block
AnalyticBlock myBlock = AnalyticBlock.Create(availableAnalytics[2]);
myBlock.Name = "MyBlockName";

 

Configuring analytic inputs of the Analytic Block

C#:

// Iterate through Analytic inputs and determine what class types they are
foreach (AnalyticBlock.InputConfiguration input in myBlock.Inputs)
{
   if (input.IsSingle)
   {
       AnalyticBlock.SingleInputConfiguration singleInput = (AnalyticBlock.SingleInputConfiguration) (input);
   }
   else
   {
       AnalyticBlock.VariableInputConfiguration variableInput = (AnalyticBlock.VariableInputConfiguration) (input);
   }
}

// Set the value of a Single Analytic input
AnalyticBlock.InputConfiguration firstSingleInput = myBlock.Inputs[0];
if (firstSingleInput.GetType() == typeof(AnalyticBlock.SingleInputConfiguration))
{
   AnalyticBlock.SingleInputConfiguration singleInput = (AnalyticBlock.SingleInputConfiguration)(firstSingleInput); singleInput.MappedField = "MyMappedFieldName";
}

// Set values of a Variable Analytic input
AnalyticBlock.InputConfiguration firstVariableInput = myBlock.Inputs[0];
if (firstVariableInput.GetType() == typeof(AnalyticBlock.VariableInputConfiguration))
{
   AnalyticBlock.VariableInputConfiguration variableInput = (AnalyticBlock.VariableInputConfiguration)(firstVariableInput);

  // Check if this input is variable or not. NB! Even though this is a VariableInputConfiguration, the IsVariable flag can
  // still be false, indicating that there are either 0 or 1 value to this input. Only inputs that are required to be a single value are of type SingleInputConfiguration!
   if (!variableInput.IsVariable)
   {

       // NOTE: This is set exactly like the SingleInputConfiguration, because it has only one value.
       variableInput.MappedField = "MyMappedFieldName";  
   }
   else
  {
       // Either use GetMappedFieldCount() on the 'variableInput' to see how many inputs are required, or just set the
       // number manually. NOTE: If the input can only have 1 value or no value, the amount of values set with SetMappedFieldCount() cannot exceed 1.
       variableInput.SetMappedFieldCount(3);
       variableInput.SetMappedField(0, "MyFirstMappedField");
       variableInput.SetMappedField(1, "MySecondMappedField");
       variableInput.SetMappedField(2, "MyThirdMappedField");
   }
}

 

 

Configuring analytic outputs of the Analytic Block

C#:

// Iterate through Analytic outputs and determine what class types they are
foreach (AnalyticBlock.OutputConfiguration output in myBlock.Outputs)
{
   if (output.IsSingle)
   {
       AnalyticBlock.SingleOutputConfiguration singleOutput = (AnalyticBlock.SingleOutputConfiguration)(output);
   }
   else
   {
       AnalyticBlock.VariableOutputConfiguration variableOutput = (AnalyticBlock.VariableOutputConfiguration)(output);
   }
}

// Set the value of a Single Analytic output
AnalyticBlock.OutputConfiguration firstSingleOutput = myBlock.Outputs[0];
if (firstSingleOutput.GetType() == typeof(AnalyticBlock.SingleOutputConfiguration))
{
   AnalyticBlock.SingleOutputConfiguration singleOutput = (AnalyticBlock.SingleOutputConfiguration)(firstSingleOutput);
   singleOutput.MappedOutputField = new Field("MyOutputFieldName", Proficy.CSense.SDK.Field.FieldKind.Double);
    singleOutput.MappedDataModelTag = "EquipmentModelRootNode.MyEquipment.Location.Tag.Value";
}

// Set values of a Variable Analytic output
AnalyticBlock.OutputConfiguration firstVariableOutput = myBlock.Outputs[0];
if (firstVariableOutput.GetType() == typeof(AnalyticBlock.VariableOutputConfiguration))
{
   AnalyticBlock.VariableOutputConfiguration variableOutput = (AnalyticBlock.VariableOutputConfiguration)(firstVariableOutput);

   // Check if this output is variable or not. NB! Even though this is a VariableOutputConfiguration, the
   // IsVariable flag can still be false, indicating that  there are either 0 or 1 value to this output. Only
   // outputs that are required to be a single value are of type SingleOutputConfiguration!
   if (!variableOutput.IsVariable)
   {

       // NOTE: This is set exactly like the SingleOutputConfiguration, because it has only one value.

       variableOutput.MappedOutputField = new Proficy.CSense.SDK.Field("MyOutputFieldName", Proficy.CSense.SDK.Field.FieldKind.Double);
       variableOutput.MappedDataModelTag = "EquipmentModelRootNode.MyEquipment.Location.Tag.Value"; }
   }
   else
   {
       // Either use GetOutputCount() on the 'variableOutput' to see how many outputs are required, or
       // just set the number manually. NOTE: If the output can only have 1 value or no value, the
       // amount of values set with SetMappedFieldCount() cannot exceed 1.
       variableOutput.SetOutputCount(2);
       variableOutput.SetMappedOutputField(0, new Proficy.CSense.SDK.Field("MyFirstMappedField", Proficy.CSense.SDK.Field.FieldKind.Integer));
       variableOutput.SetMappedOutputField(1, new Proficy.CSense.SDK.Field("MySecondMappedField", Proficy.CSense.SDK.Field.FieldKind.String));
       variableOutput.SetMappedDataModelTag(1, "EquipmentModelRootNode.MyEquipment.Location.MySecondTag.Value");
   }
}

 

Configuring analytic properties of the Analytic Block

C#:

// Iterate through Analytic properties and determine what class types they are
foreach (AnalyticBlock.PropertyConfiguration analyticProperty in myBlock.Properties)
{
   if (analyticProperty.IsSingle)
   {

       // Single Value Property Types
       if (analyticProperty.GetType() == typeof(AnalyticBlock.SingleDoublePropertyConfiguration))
       {
           AnalyticBlock.SingleDoublePropertyConfiguration singleDoubleProperty = (AnalyticBlock.SingleDoublePropertyConfiguration)(analyticProperty);
       }
       else if (analyticProperty.GetType() == typeof(AnalyticBlock.SingleIntegerPropertyConfiguration))
       {
           AnalyticBlock.SingleIntegerPropertyConfiguration singleIntegerProperty = (AnalyticBlock.SingleIntegerPropertyConfiguration)(analyticProperty);
       }
       else if (analyticProperty.GetType() == typeof(AnalyticBlock.SingleStringPropertyConfiguration))
       {
           AnalyticBlock.SingleStringPropertyConfiguration singleStringProperty = (AnalyticBlock.SingleStringPropertyConfiguration)(analyticProperty);
       }
       else if (analyticProperty.GetType() == typeof(AnalyticBlock.SingleEnumerationPropertyConfiguration))
       {
           AnalyticBlock.SingleEnumerationPropertyConfiguration singleEnumerationProperty = (AnalyticBlock.SingleEnumerationPropertyConfiguration)(analyticProperty);
       }
   }
   else
   {
       // Multiple Value Property Types
       if (analyticProperty.GetType() == typeof(AnalyticBlock.VariableDoublePropertyConfiguration))
       {
           AnalyticBlock.VariableDoublePropertyConfiguration variableDoubleProperty = (AnalyticBlock.VariableDoublePropertyConfiguration)(analyticProperty);
       }
       else if (analyticProperty.GetType() == typeof(AnalyticBlock.VariableIntegerPropertyConfiguration))
       {
           AnalyticBlock.VariableIntegerPropertyConfiguration variableIntegerProperty = (AnalyticBlock.VariableIntegerPropertyConfiguration)(analyticProperty);
       }
       else if (analyticProperty.GetType() == typeof(AnalyticBlock.VariableStringPropertyConfiguration))
       {
           AnalyticBlock.VariableStringPropertyConfiguration variableStringProperty = (AnalyticBlock.VariableStringPropertyConfiguration)(analyticProperty);
       }
       else if (analyticProperty.GetType() == typeof(AnalyticBlock.VariableEnumerationPropertyConfiguration))
       {
           AnalyticBlock.VariableEnumerationPropertyConfiguration variableEnumerationProperty = (AnalyticBlock.VariableEnumerationPropertyConfiguration)(analyticProperty);
       }
   }
}

// Set the value of a Single Analytic property
// Assume you know that the property at index 4 is a single double property
AnalyticBlock.SingleDoublePropertyConfiguration mySingleDoubleProperty = (AnalyticBlock.SingleDoublePropertyConfiguration) (myBlock.Properties[4]);
double myValueToSet = 1.538;

// You can check the ranges that the value may be (only for double or integer types!). You can also
// check if that range on the value border is inclusive or not.

if ((myValueToSet > mySingleDoubleProperty.Minimum) && (mySingleDoubleProperty.HasMinimum)
&& (myValueToSet < mySingleDoubleProperty.Maximum) && (mySingleDoubleProperty.HasMaximum))
{
   mySingleDoubleProperty.DoubleValue = 1.538;
}

// Set the values of Variable Analytic properties
// Assume you know that the property at index 2 is a variable enumeration property
AnalyticBlock.VariableEnumerationPropertyConfiguration myVariableEnumerationProperty = (AnalyticBlock.VariableEnumerationPropertyConfiguration)(myBlock.Properties[2]);

// Use GetValueCount() to get the default number or set a new number of values on the property
myVariableEnumerationProperty.SetValueCount(3);

// You can check if your value is in a list of valid enumeration values on the property
if (myVariableEnumerationProperty.EnumerationValues.Contains("FirstValue"))
{
   myVariableEnumerationProperty.SetValue(0, "FirstValue");
}

myVariableEnumerationProperty.SetValue(1, "SecondValue");
myVariableEnumerationProperty.SetValue(2, "ThirdValue");

// Set value(s) on composite properties on a property
AnalyticBlock.SingleIntegerPropertyConfiguration mySingleIntegerProperty = (AnalyticBlock.SingleIntegerPropertyConfiguration)(myBlock.Properties[0]);

if (mySingleIntegerProperty.HasSubProperties)
{
   foreach (AnalyticBlock.PropertyConfiguration subProperty in mySingleIntegerProperty.SubProperties)
   {

      // Check the type of the subproperty (like above examples) and set the property value(s) accordingly.
      // Even these properties might have subproperties (ad infinitum), so to get to all subproperties,
you might need a recursive method!
   }
}

 

Configuring and executing the Analytic with Analytic Executor

C#:

// Get Analytic from the repository
AnalyticRepository^ myRepository = gcnew AnalyticRepository();
Analytic^ myAnalytic = myRepository->GetAnalytic(L"MyAnalytic", L"1");

// Pass the analytic into the executor
// true = keep state during execution
// false = no state kept during execution
AnalyticExecutor^ myExecutor = AnalyticExecutor::Create(myAnalytic, true);
DateTime myExecutetTime = DateTime::Now;

// Set the input values
for (int dataEventSetIndex = 0; dataEventSetIndex < numberOfDataEventSets; ++dataEventSetIndex)
{

   // One dataeventset is added by default so the user only needs to add dataeventsets on the second iteration
   if (dataEventSetIndex > 0)
   {
       myExecutor->AddDataEventSet();
   }

   Proficy::CSense::SDK::Runtime::AnalyticExecutor::DataEventSet^ myDataEvent = myExecutor->InputDataEventSets[dataEventSetIndex];

   myDataEvent->Timestamp = myExecutetTime;

   // Set the values for each field
   for (int fieldIndex = 0; fieldIndex < myExecutor->InputFields->Count; ++fieldIndex)
   {
       AnalyticExecutor::FieldValue^ myField = myDataEvent[myExecutor->InputFields[fieldIndex]];
       if (myField->GetType() == AnalyticExecutor::DMReal::typeid)
       {
           AnalyticExecutor::DMReal^ myDoubleValue = safe_cast<AnalyticExecutor::DMReal^> (myDataEvent[myExecutor->InputFields[fieldIndex]]);
           myDoubleValue->Timestamp = myExecutetTime;
           myDoubleValue->Value = 10;
       }
       else if (myField->GetType() == AnalyticExecutor::DMInt::typeid)
       {
           AnalyticExecutor::DMInt^ myIntegerValue = safe_cast<AnalyticExecutor::DMInt^> (myDataEvent[myExecutor->InputFields[fieldIndex]]);
           myIntegerValue->Timestamp = myExecutetTime;
           myIntegerValue->Value = 100;
       }
       else if (myField->GetType() == AnalyticExecutor::DAString::typeid)
       {
           AnalyticExecutor::DAString^ myStringValue = safe_cast<AnalyticExecutor::DAString^> (myDataEvent[myExecutor->InputFields[fieldIndex]]);
           myStringValue->Timestamp = myExecutetTime;
           myStringValue->Value = L"MyString";
       }
   } // for each input

   // make sure to increase the execute time
   myExecutetTime = myExecutetTime.AddMinutes(1);
} // for each row

bool success = myExecutor->Execute();
if(success)
{
   for each (AnalyticExecutor::DataEventSet^ myDataEvent in myExecutor->OutputDataEventSets)
   {
       for each (AnalyticExecutor::FieldInformation^ myInfo in myExecutor->OutputFields)
       {
           AnalyticExecutor::FieldValue^ myField = myDataEvent[myInfo];
           if (myField->GetType() == AnalyticExecutor::DMReal::typeid)
           {
               AnalyticExecutor::DMReal^ myDoubleValue = safe_cast<AnalyticExecutor::DMReal^> (myDataEvent[myInfo]);
               double myOutputValue = myDoubleValue->Value;
           }
           else if (myField->GetType() == AnalyticExecutor::DMInt::typeid)
           {
               AnalyticExecutor::DMInt^ myIntegerValue = safe_cast<AnalyticExecutor::DMInt^> (myDataEvent[myInfo]);
               int myOutputValue = myIntegerValue->Value;
           }
           else if (myField->GetType() == AnalyticExecutor::DAString::typeid)
           {
               AnalyticExecutor::DAString^ myStringValue = safe_cast<AnalyticExecutor::DAString^> (myDataEvent[myInfo]);
               String^ myOutputValue = myStringValue->Value;
           }
       } // for each output field
   } // for each row
}    

 

 

  

CSense 2023- Last updated: June 24,2025